<template>
  <el-container style="height: 100vh">
    <!-- 左侧列表 -->
    <el-aside width="300px" class="aside">
      <div class="aside-header">流程定义列表</div>
      <el-scrollbar>
        <el-menu :default-active="activeId" class="menu" @select="handleSelect">
          <el-menu-item
            v-for="item in processList"
            :key="item.id"
            :index="item.id"
            class="menu-item"
          >
            <div class="menu-item-content">
              <div class="menu-title">{{ item.name }}</div>

              <div
                v-if="
                  processInstance &&
                  item.id === processInstance.processDefinitionId
                "
                class="menu-sub"
              >
                <span class="started"
                  >Started {{ formatTimeAgo(processInstance.startTime) }}</span
                >
                <span class="by">· by {{ processInstance.startUserId }}</span>
              </div>
            </div>
          </el-menu-item>
        </el-menu>
      </el-scrollbar>
    </el-aside>

    <!-- 右侧详情 -->
    <el-main class="main">
      <template v-if="activeProcess">
        <h2>{{ activeProcess.name }}</h2>
        <el-descriptions :column="1" border>
          <el-descriptions-item label="ID">
            {{ activeProcess.id }}
          </el-descriptions-item>
          <el-descriptions-item label="Key">
            {{ activeProcess.key }}
          </el-descriptions-item>
          <el-descriptions-item label="Version">
            {{ activeProcess.version }}
          </el-descriptions-item>
          <el-descriptions-item label="Description">
            {{ activeProcess.description || "无描述" }}
          </el-descriptions-item>
          <el-descriptions-item label="processInstanceId">
            {{ processInstance ? processInstance.id : "未启动" }}
          </el-descriptions-item>
        </el-descriptions>

        <div class="actions">
          <template v-if="!processInstance">
            <el-button type="primary" @click="startProcess">启动流程</el-button>
          </template>
          <template v-else>
            <el-button type="success" @click="openDiagramDialog">
              查看流程图
            </el-button>
            <el-button type="danger" @click="cancelProcess">
              取消流程
            </el-button>
          </template>
        </div>
      </template>

      <el-empty v-else description="请选择一个流程定义" />
    </el-main>

    <!-- 弹出层 -->
    <el-dialog
      title="流程图"
      v-model="diagramVisible"
      width="80%"
      :before-close="closeDiagramDialog"
    >
      <div ref="viewerContainer" style="width: 100%; height: 600px; border: 1px solid #ebeef5"></div>
    </el-dialog>
  </el-container>
</template>

<script setup lang="ts">
import { FlowableService } from "@/api/flowableService";
import { ElMessage, ElMessageBox } from "element-plus";
import { nextTick, onMounted, ref } from "vue";

import { useFlowableStore } from "@/stores/flowableStore";

import BpmnViewer from "bpmn-js/lib/NavigatedViewer";
import type Canvas from "diagram-js/lib/core/Canvas";

import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import "dayjs/locale/zh-cn";
dayjs.extend(relativeTime);
dayjs.locale("zh-cn");

const formatTimeAgo = (time: string) => dayjs(time).fromNow();

const service = new FlowableService(
  "/api/flowable-task/process-api",
  "jack",
  "123456"
);
const processList = ref<any[]>([]);
const activeId = ref<string>("");
const activeProcess = ref<any | null>(null);

const store = useFlowableStore();
const processInstance = ref<any | null>(store.lastInstance);

// 弹窗相关
const diagramVisible = ref(false);
const viewerContainer = ref<HTMLElement | null>(null);
let viewer: BpmnViewer | null = null;

onMounted(async () => {
  processList.value = await service.listProcessDefinitions();

  if (processInstance.value) {
    activeId.value = processInstance.value.processDefinitionId;
    activeProcess.value = processList.value.find(
      (p) => p.id === activeId.value
    );
  }
});

const handleSelect = (id: string) => {
  activeId.value = id;
  activeProcess.value = processList.value.find((p) => p.id === id);
};

/**
 * 启动流程
 */
const startProcess = async () => {
  if (!activeProcess.value) return;
  try {
    const res = await service.startProcessInstance({
      processDefinitionId: activeProcess.value.id,
    });
    ElMessage.success("流程启动成功");
    processInstance.value = res;
    store.setInstance(res); // ✅ 持久化
    console.log("启动结果:", res);
  } catch (err) {
    ElMessage.error("启动流程失败");
  }
};

// 取消流程
const cancelProcess = async () => {
  if (!processInstance.value) return;
  try {
    await ElMessageBox.confirm(
      "确定要取消该流程实例吗？此操作不可恢复。",
      "警告",
      { type: "warning" }
    );
    const success = await service.deleteProcessInstance(
      processInstance.value.id,
      "用户主动取消流程"
    );
    if (success) {
      store.clearInstance();
      processInstance.value = null;
      ElMessage.success("流程已取消");
    } else {
      ElMessage.warning("取消流程实例失败");
    }
  } catch (err) {
    console.error(err);
    ElMessage.error("请求出错，取消失败");
  }
};

// 查看所有流程实例
const allProcessInstances = async () => {
  const list = await service.listProcessInstances();
  // 如果流程实例数组长度为0，清空持久化
  if (list.length === 0) {
    store.clearInstance();
    processInstance.value = null;
  }
  // 将list中与当前定义ID匹配的实例设为当前实例
  else { 
    const matched = list.find(
      (inst) => inst.processDefinitionId === activeId.value
    );
    if (matched) {
      processInstance.value = matched;
      store.setInstance(matched); // ✅ 持久化
    } else {
      processInstance.value = null;
    }
  }
};

defineExpose({
  allProcessInstances
});

// 打开弹窗显示流程图
const openDiagramDialog = async () => {
  if (!activeProcess.value || !processInstance.value) return;
  diagramVisible.value = true;

  await nextTick();

  if (!viewerContainer.value) return;

  try {
    const xml = await service.getProcessXml(activeProcess.value.id);
    const activeIds = await service.getActiveActivities(processInstance.value.id);

    console.log(activeIds)

    viewer = new BpmnViewer({ container: viewerContainer.value });
    await viewer.importXML(xml);

    const canvas = viewer.get<Canvas>("canvas");
    canvas.zoom("fit-viewport");

    activeIds.forEach((id) => canvas.addMarker(id, "highlight"));
  } catch (err) {
    console.error(err);
    ElMessage.error("加载流程图失败");
  }
};

// 关闭弹窗
const closeDiagramDialog = () => {
  diagramVisible.value = false;
  if (viewer) {
    viewer.destroy();
    viewer = null;
  }
};
</script>

<style scoped>
.aside {
  border-right: 1px solid #ebeef5;
  display: flex;
  flex-direction: column;
}

.aside-header {
  font-weight: bold;
  padding: 12px;
  background: #f5f7fa;
  border-bottom: 1px solid #ebeef5;
}

.menu-item {
  line-height: 1.4;
  padding-top: 8px !important;
  padding-bottom: 8px !important;
  display: flex;
  align-items: flex-start;
  flex-direction: column;
}
.menu-item-content {
  width: 100%;
}
.menu-title {
  font-weight: 500;
  font-size: 14px;
  color: #303133;
}
.menu-sub {
  font-size: 12px;
  color: #909399;
  margin-top: 4px;
}
.menu-sub .started {
  color: #67c23a;
  font-weight: 500;
}

.menu-sub .by {
  color: #909399;
}

.main {
  padding: 20px;
}

.actions {
  margin-top: 20px;
}

::v-deep(.djs-element.highlight .djs-visual > :nth-child(1)) {
  stroke: blue !important;
  stroke-width: 4px !important;
}
</style>
